package info.emamian.droplet.worker.controllers;

import info.emamian.droplet.controllers.AbstractDropletWorkerController;
import info.emamian.droplet.data.DynamoDbSms;
import info.emamian.droplet.data.SystemEventsDynamoDB;
import info.emamian.droplet.worker.sms.SMSService;

import java.util.Date;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * Handles requests for the application home page.
 */

@Controller
public class WorkerController extends AbstractDropletWorkerController {

	private static final Logger LOGGER = LoggerFactory
			.getLogger(WorkerController.class);
	private static Long CONTROLLER_COUNT = 0L;
	private static long DURATION_SUM = 0;
	private static long DURATION_COUNT = 0;
	@Autowired
	SMSService smsService;

	// ----
	@Value("${propertyValueString:myDefaultValueString}")
	private String propertValueString;

	@Autowired
	private Environment env;// env.getProperty("propertyValueString");

	// ----

	private static void logDuration(final long start_time, final long end_time) {
		DURATION_SUM += end_time - start_time;
		DURATION_COUNT++;
		if (DURATION_COUNT % 100 == 99) {
			LOGGER.info("response count [{}], avg duration:[{}]",
					DURATION_COUNT, (DURATION_SUM / DURATION_COUNT));
		}
	}

	@PostConstruct
	public void postConstruct() {

		synchronized (CONTROLLER_COUNT) {
			CONTROLLER_COUNT++;
			this.setWorker_id(CONTROLLER_COUNT.longValue());
		}
		try {
			SystemEventsDynamoDB ev = new SystemEventsDynamoDB();
			ev.setDate(new Date());
			ev.setMessageType("worker");
			ev.setMessage("worker " + this.getWorker_id() + " created");
			getDbMapper().save(ev);
		} catch (Exception e) {
			LOGGER.error("Exception , ", e);
		}
		LOGGER.info("--postConstruct: worker {} created.", this.getWorker_id());
	}

	@RequestMapping(value = "/", method = RequestMethod.POST)
	public void work(final HttpServletRequest request,
			final HttpServletResponse response, @RequestBody final String body) {
		long start_time = new Date().getTime();
		try {
			System.out.println("received " + new Date().getTime());

			// validate input
			if (body == null) {
				LOGGER.error("body was null");
				response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
				return;
			}

			// load input sms from dynamoDb
			DynamoDbSms sms = getDbMapper().load(DynamoDbSms.class, body);
			if (sms == null) {
				LOGGER.error("sms was null for body [{}]", body);
				response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
				return;
			}

			// get response for sms
			String responseText = smsService
					.getAnswerFromAppropriateHandler(sms);
			Date end_date = new Date();
			long end_time = end_date.getTime();

			// update sms object with response and set its flag
			saveSmsResponse(sms, 1, responseText, end_date);
			logDuration(start_time, end_time);

			if (LOGGER.isDebugEnabled()) {
				LOGGER.debug(String
						.format("worker%s -- Received on: [%s], answered on: [%s], duration:[%s], sms response to [%s] is [%s]",
								this.getWorker_id(), start_time, end_time,
								(end_time - start_time), sms.getBody(),
								responseText));
			}
		} catch (Exception e) {
			LOGGER.error(
					"Exception in work, duration: "
							+ (new Date().getTime() - start_time), e);
		} finally {
			if (LOGGER.isDebugEnabled()) {
				LOGGER.debug("worker{} -- Work Duration: {}", this.getWorker_id(),
						(new Date().getTime() - start_time));
			}
		}
	}

	private void saveSmsResponse(final DynamoDbSms sms, final int flag,
			final String answer, final Date end_date) {
		sms.setFlag(1);
		sms.setAnswer(answer);
		sms.setUpdatedTime(end_date);
		getDbMapper().save(sms);
	}

	@PreDestroy
	public void finalStatistics() {
		if (DURATION_COUNT > 0) {
			LOGGER.info(String.format("request count [%s], avg duration [%s]",
					DURATION_COUNT, (DURATION_SUM / DURATION_COUNT)));
		}
		try {
			SystemEventsDynamoDB ev = new SystemEventsDynamoDB();
			ev.setDate(new Date());
			ev.setMessageType("worker");
			ev.setMessage("worker " + this.getWorker_id() + " destroyed");
			getDbMapper().save(ev);
		} catch (Exception e) {
			LOGGER.error("Exception , ", e);
		}

	}

}
